package com.yuhuihui.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * jackson工具类
 *
 * @author yuhh
 * @date 2023-05-25 14:20:07
 */
public final class JacksonUtil {

    /** logger */
    private static final Logger logger = LoggerFactory.getLogger(JacksonUtil.class);

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /** 日期格式 */
    private static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";

    static {
        // 对象的所有字段全部列入
        OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        // 取消默认转换timestamps形式
        OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        // 忽略空Bean转json的错误
        OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
        // 所有的日期格式都统一为以下的样式，即yyyy-MM-dd HH:mm:ss
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat(STANDARD_FORMAT));
        // 忽略在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
    }

    /**
     * 对象转Json格式字符串
     *
     * @param obj 对象
     * @return {@link String } Json格式字符串
     * @author yuhh
     * @date 2023-05-25 14:20:21
     */
    public static <T> String obj2String(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.error("对象转Json格式字符串出现异常", e);
            return null;
        }
    }

    /**
     * 转换为 JSON 字符串，忽略空值
     *
     * @param obj 对象
     * @return {@link String } Json格式字符串
     * @author yuhh
     * @date 2023-05-25 14:20:25
     */
    public static <T> String obj2StringIgnoreNull(T obj) {
        if (obj == null) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.error("对象转Json格式字符串出现异常", e);
            return null;
        }
    }

    /**
     * 字符串转换为自定义对象
     *
     * @param str   要转换的字符串
     * @param clazz 自定义对象的class对象
     * @return {@link T } 自定义对象
     * @author yuhh
     * @date 2023-05-25 14:20:32
     */
    public static <T> T string2Obj(String str, Class<T> clazz){
        if(ObjectUtils.isEmpty(str) || clazz == null){
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(str, clazz);
        } catch (Exception e) {
            logger.error("字符串转换为自定义对象出现异常", e);
            return null;
        }
    }

    /**
     * 字符串转换为指定类型
     *
     * @param str           要转换的字符串
     * @param typeReference 类型参考
     * @return {@link T } 自定义对象
     * @author yuhh
     * @date 2023-05-25 14:20:38
     */
    public static <T> T string2Obj(String str, TypeReference<T> typeReference) {
        if (ObjectUtils.isEmpty(str) || typeReference == null) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(str, typeReference);
        } catch (IOException e) {
            logger.error("字符串转换为指定类型出现异常", e);
            return null;
        }
    }

    /**
     * 将JSON数组转换为集合
     *
     * @param str   要转换的字符串
     * @param clazz 自定义对象的class对象
     * @return {@link List }<{@link T }> 自定义对象列表
     * @author yuhh
     * @date 2023-05-25 14:20:48
     */
    public static <T> List<T> json2list(String str, Class<T> clazz) {
        JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(ArrayList.class, clazz);
        try {
            return OBJECT_MAPPER.readValue(str, javaType);
        } catch (JsonProcessingException e){
            logger.error("将JSON数组转换为集合出现异常", e);
        }
        return null;
    }

    /**
     * 将String转为JsonNode
     *
     * @param str 要转换的字符串
     * @return {@link JsonNode }
     * @author yuhh
     * @date 2023-05-25 14:20:56
     */
    public static JsonNode string2JsonNode(String str) {
        if (ObjectUtils.isEmpty(str)) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readTree(str);
        } catch (IOException e) {
            logger.error("将String转为JsonNode出现异常", e);
            return null;
        }
    }

    /**
     * jsonNode转List
     *
     * @param jsonNode 需要转换的jsonNode
     * @param clazz    需要转换成的object的class
     * @return {@link List }<{@link T }> 转换后的List
     * @author yuhh
     * @date 2023-05-25 14:21:06
     */
    public static <T> List<T> jsonNode2List(JsonNode jsonNode, Class<T> clazz) {
        if (!jsonNode.isArray()) {
            throw new RuntimeException("json对象不是数组类型");
        }
        List<T> result = new ArrayList<>();
        for (JsonNode node : jsonNode) {
            T t = jsonNode2Obj(node, clazz);
            if (t != null){
                result.add(t);
            }
        }
        return result;
    }

    /**
     * jsonNode转object
     *
     * @param jsonNode 需要转换的jsonNode
     * @param clazz    需要转换成的object的class
     * @return {@link T } 转换后的object
     * @author yuhh
     * @date 2023-05-25 14:21:10
     */
    public static <T> T jsonNode2Obj(JsonNode jsonNode, Class<T> clazz){
        if (!jsonNode.isObject()){
            throw new RuntimeException("json对象不是对象类型");
        }
        try {
            return OBJECT_MAPPER.treeToValue(jsonNode, clazz);
        } catch (JsonProcessingException e) {
            logger.error("jsonNode转object出现异常", e);
        }
        return null;
    }

    public static <T> T map2Obj(Map<?, ?> map, Class<T> clazz){
        try {
            return OBJECT_MAPPER.convertValue(map, clazz);
        } catch (IllegalArgumentException e) {
            logger.error("map转object出现异常", e);
        }
        return null;
    }
}
